<PageCard className="mb-8">

# size

Provides data to change the size of a floating element.

<MiddlewareContainer>
  <MiddlewareBadge type="Visibility Optimizer" />
  <MiddlewareBadge type="Data Provider" />
</MiddlewareContainer>

<ShowFor packages={['core']}>

```js
import {size} from '@floating-ui/core';
```

</ShowFor>

<ShowFor packages={['dom']}>

```js
import {size} from '@floating-ui/dom';
```

</ShowFor>

<ShowFor packages={['react']}>

```js
import {size} from '@floating-ui/react';
```

</ShowFor>

<ShowFor packages={['react-dom']}>

```js
import {size} from '@floating-ui/react-dom';
```

</ShowFor>

<ShowFor packages={['vue']}>

```js
import {size} from '@floating-ui/vue';
```

</ShowFor>

<ShowFor packages={['react-native']}>

```js
import {size} from '@floating-ui/react-native';
```

</ShowFor>

This is useful to ensure the floating element isn't too big to
fit in the viewport (or more specifically, its clipping context),
especially when a maximum size isn't specified. It also allows
matching the width/height of the reference element.

</PageCard>

<div className="flex flex-col gap-4">
  <Chrome
    label="Scroll the container"
    center
    scrollable="y"
    className="h-96"
  >
    <Floating
      tooltipStyle={{
        height: 300,
        overflow: 'hidden',
        maxHeight: 0,
      }}
      middleware={[
        {
          name: 'size',
          options: {padding: 5, rootBoundary: 'document'},
        },
      ]}
    >
      <div className="grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000" />
    </Floating>
  </Chrome>
</div>

## Usage

If your floating element's content cannot be resized such as in
the example, you can make the floating element scrollable with
`overflow: scroll{:sass}` (or `auto{:.param}`). Ensure your CSS
is using `box-sizing: border-box{:sass}`!

<ShowFor packages={['core']}>

```js
computePosition(referenceEl, floatingEl, {
  middleware: [
    size({
      apply({availableWidth, availableHeight, elements}) {
        // Change styles
      },
    }),
  ],
});
```

</ShowFor>

<ShowFor packages={['dom']}>

```js
computePosition(referenceEl, floatingEl, {
  middleware: [
    size({
      apply({availableWidth, availableHeight, elements}) {
        // Change styles, e.g.
        Object.assign(elements.floating.style, {
          maxWidth: `${availableWidth}px`,
          maxHeight: `${availableHeight}px`,
        });
      },
    }),
  ],
});
```

</ShowFor>

<ShowFor packages={['vue']}>

```js
useFloating(reference, floating, {
  middleware: [
    size({
      apply({availableWidth, availableHeight, elements}) {
        // Change styles, e.g.
        Object.assign(elements.floating.style, {
          maxWidth: `${availableWidth}px`,
          maxHeight: `${availableHeight}px`,
        });
      },
    }),
  ],
});
```

</ShowFor>

<ShowFor packages={['react', 'react-dom']}>

1. You can use sync state, and apply using the `style{:.keyword}`
   prop during render, achieved via `flushSync(){:js}`:

```js
import {flushSync} from 'react-dom';
```

```js {6-8}  /maxHeight/
const [maxHeight, setMaxHeight] = useState(null);

const {refs, floatingStyles} = useFloating({
  middleware: [
    size({
      apply({availableHeight}) {
        flushSync(() => setMaxHeight(availableHeight));
      },
    }),
  ],
});

return (
  <div
    ref={refs.setFloating}
    style={{...floatingStyles, maxHeight}}
  />
);
```

2. Or, mutate the style property directly:

```js
useFloating({
  middleware: [
    size({
      apply({availableHeight, elements}) {
        elements.floating.style.maxHeight = `${availableHeight}px`;
      },
    }),
  ],
});
```

</ShowFor>

## Options

These are the options you can pass to `size(){:js}`.

```ts
interface SizeOptions extends DetectOverflowOptions {
  apply?: (
    state: MiddlewareState & {
      availableWidth: number;
      availableHeight: number;
    },
  ) => void;
}
```

### `apply{:.function}`

default: `undefined{:js}`

Unlike other middleware, in which you assign styles after
`computePosition(){:js}` has done its work, `size(){:js}` has its
own `apply{:.function}` function to do the work during the
lifecycle:

```js
size({
  apply({availableWidth, availableHeight, ...state}) {
    // Style mutations here
  },
});
```

#### `availableWidth{:.param}`

Represents how wide the floating element can be before it will
overflow its clipping context. You'll generally set this as the
`maxWidth{:.key}` CSS property.

#### `availableHeight{:.param}`

Represents how tall the floating element can be before it will
overflow its clipping context. You'll generally set this as the
`maxHeight{:.key}` CSS property.

#### ...middlewareState

See [MiddlewareState](/docs/middleware#middlewarestate).

Many useful properties are also accessible via this callback,
such as `rects{:.key}` and `elements{:.key}`.

### ...detectOverflowOptions

All of [`detectOverflow`](/docs/detectOverflow#options)'s options
can be passed. For instance:

```js
size({padding: 5}); // 0 by default
```

### Deriving options from state

You can derive the options from the
[middleware lifecycle state](/docs/middleware#middlewarestate):

```js
size((state) => ({
  padding: state.rects.reference.width,
}));
```

## Using with `flip(){:js}`

Using `size(){:js}` together with `flip(){:js}` enables some
useful behavior. The floating element can be resized, thus
allowing it to prefer its initial placement as much as possible,
until it reaches a minimum size, at which point it will flip.

If you're using the `padding{:.key}` option in either middleware,
ensure they share the **same value**.

### `bestFit{:.string}`

The `'bestFit'{:js}` fallback strategy in the `flip(){:js}`
middleware is the default, which ensures the best fitting
placement is used. In this scenario, place `size(){:js}`
**after** `flip(){:js}`:

```js
const middleware = [
  flip(),
  size({
    apply({availableWidth, availableHeight}) {
      // ...
    },
  }),
];
```

<div className="flex flex-col gap-4">
  <Chrome
    label="Scroll the container"
    center
    scrollable="y"
    className="h-96"
  >
    <Floating
      tooltipStyle={{
        height: 200,
        overflow: 'hidden',
        maxHeight: 0,
      }}
      middleware={[
        {
          name: 'flip',
          options: {padding: 5, rootBoundary: 'document'},
        },
        {
          name: 'size',
          options: {padding: 5, rootBoundary: 'document'},
        },
      ]}
    >
      <div className="grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000" />
    </Floating>
  </Chrome>
</div>

This strategy ensures the floating element stays in view at all
times at the most optimal size.

### `initialPlacement{:.string}`

If instead, you want the initial placement to take precedence,
and are setting a minimum acceptable size, place `size(){:js}`
**before** `flip(){:js}`:

```js {12}
const middleware = [
  size({
    apply({availableHeight, elements}) {
      Object.assign(elements.floating.style, {
        // Minimum acceptable height is 50px.
        // `flip` will then take over.
        maxHeight: `${Math.max(50, availableHeight)}px`,
      });
    },
  }),
  flip({
    fallbackStrategy: 'initialPlacement',
  }),
];
```

## Match reference width

A common feature of select dropdowns is that the dropdown matches
the width of the reference regardless of its contents. You can
also use `size(){:js}` for this, as the `Rect{:.class}`s get
passed in:

```js
size({
  apply({rects, elements}) {
    Object.assign(elements.floating.style, {
      width: `${rects.reference.width}px`,
    });
  },
});
```
